/* 
 * Copyright (c) 2012, Fromentin Xavier, Schnell Michaël, Dervin Cyrielle, Brabant Quentin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *      * The names of its contributors may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Fromentin Xavier, Schnell Michaël, Dervin Cyrielle OR Brabant Quentin 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package kameleon.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

import kameleon.document.Document;
import kameleon.exception.FileReadingException;
import kameleon.exception.FileWritingException;

/**
 * Utility class for writing and reading instances of {@code Document}.
 * 
 * @author		Schnell Michaël
 * @version		1.0	
 */
public class IODocument {

	/**
	 * Sole constructor.
	 */
	private IODocument() {
		super() ;
	}// IODocument()

	/**
	 * Writes the given instance of {@code Document} to the file with the given path.
	 * 
	 * @param 	document
	 * 			instance written in the file	
	 * 
	 * @param 	path
	 * 			path of the target file
	 * 
	 * @throws 	FileWritingException
	 * 			if the file cannot be created or there is an error while writing
	 * 
	 * @see		#writeToFile(Document, File)
	 */
	public static void writeToFile(Document document, String path) throws FileWritingException {
		writeToFile(document, new File(path)) ;
	}// writeToFile(Document, String)

	/**
	 * Writes the given instance of {@code Document} to the given file.
	 * 
	 * @param 	document
	 * 			instance written in the file	
	 * 
	 * @param 	target
	 * 			target file
	 * 
	 * @throws 	FileWritingException
	 * 			if the file cannot be created or there is an error while writing
	 * 
	 * @see		#writeToFile(Document, OutputStream)
	 * @see		java.io.FileOutputStream#FileOutputStream(File)
	 */
	public static void writeToFile(Document document, File target) throws FileWritingException {
		try {
			writeToFile(document, new FileOutputStream(target)) ;
		} catch (IOException e) {
			throw new FileWritingException(target) ;
		}// try
	}// writeToFile(Document, File)

	/**
	 * Writes the given instance of {@code Document} to the {@code OutputStream}.
	 * 
	 * @param 	document
	 * 			instance written to the {@code OutputStream}
	 * 
	 * @param 	os
	 * 			target {@code OutputStream}
	 * 
	 * @throws 	IOException
	 * 			if an I/O error has occurred
	 * 
	 * @see		java.io.ObjectOutputStream#writeObject(Object)
	 */
	private static void writeToFile(Document document, OutputStream os) throws IOException {
		ObjectOutputStream out = new ObjectOutputStream(os) ;
		try {
			out.writeObject(document) ;
		} finally {
			out.close() ;
		}// try
	}// writeToFile(Document, OutputStream)

	/**
	 * Reads an instance of {@code Document} from the file with the given path.	
	 * 
	 * @param 	path
	 * 			path of the source file
	 * 
	 * @throws 	FileReadingException
	 * 			if the file doesn't exist or cannot be read
	 * 
	 * @return	Instance of {@code Document} read
	 * 
	 * @see		#readFromFile(File)
	 */
	public static Document readFromFile(String path) throws FileReadingException {
		return readFromFile(new File(path)) ;		
	}// readFromFile(String)

	/**
	 * Reads an instance of {@code Document} from the given file.	
	 * 
	 * @param 	source
	 * 			source file
	 * 
	 * @return	Instance of {@code Document} read
	 * 
	 * @throws 	FileReadingException
	 * 			if the file doesn't exist or cannot be read
	 */
	public static Document readFromFile(File source) throws FileReadingException {
		try {
			return readFromFile(new FileInputStream(source)) ;
		} catch (IOException e) {
			throw new FileReadingException(source) ;
		}// try
	}// readFromFile(File)

	/**
	 * Reads an instance of {@code Document} from the given {@code InputStream}.	
	 * 
	 * @param 	is
	 * 			source {@code InputStream}
	 * 
	 * @return	Instance of {@code Document} read
	 * 
	 * @throws 	IOException
	 * 			if there is an error while reading
	 */
	private static Document readFromFile(InputStream is) throws IOException {
		ObjectInputStream in = new ObjectInputStream(is) ;
		try {
			Document doc = (Document) in.readObject() ;
			in.close() ;
			return doc ;
		} catch (ClassNotFoundException e) {
			//TODO Find better solution ?
			// Throw an IOException to trigger a throw of a FileReadingException
			// in the calling function
			throw new IOException() ;
		}// try
	}// readFromFile(InputStream)

}// class IODocument